/*************************************************************

**************************************************************/
module ps2_receiver(
    input wire clk_i,           //reference clock for logic
    input wire arst_i,
    output reg data_o,
    output reg valid_o,
    //---------ps2 interface-------------
    input wire ps2_clk,
    input wire ps2_dat
);
localparam  RECEIVE = 2'h0,     //正在接收一帧
            DONE    = 2'h1;     //一帧接收完成
//状态机
reg [1:0] state;
// ps2信号时钟下降沿检测
reg ps2_clk_r0,ps2_clk_r1,ps2_clk_r2;
reg ps2_dat_r0, ps2_dat_r1, ps2_dat_r2;
wire neg_ps2_clk;
// 接受来自PS/2键盘的数据存储器
reg [7:0] ps2_byte_r;        // 来自PS/2的数据寄存器
reg [7:0] temp_data;            // 当前接受数据寄存器
reg [3:0] num;
//--------------来自外部的信号经过两级FF进行时钟域同步，避免亚稳态-----------------
always @(posedge clk or posedge arst_i) begin
if (arst_i)  begin
        ps2_clk_r0 <= 1'b0;
        ps2_dat_r0 <= 1'b0;
        ps2_clk_r1 <= 1'b0;
        ps2_dat_r1 <= 1'b0;
        ps2_clk_r2 <= 1'b0;
        ps2_dat_r2 <= 1'b0;
    end
    else begin
        ps2_clk_r0 <= ps2_clk;
        ps2_dat_r0 <= ps2_dat;
        ps2_clk_r1 <= ps2_clk_r0;
        ps2_dat_r1 <= ps2_dat_r0;
        ps2_clk_r2 <= ps2_clk_r1;
        ps2_dat_r2 <= ps2_dat_r2;
    end    
end // end always
    
assign neg_ps2_clk = ps2_clk_r2 & (~ps2_clk_r1);

always@(posedge clk_i or posedge arst_i)begin
    if(arst_i)begin
        num <= 0;
        temp_data <= 8'd0;
    end
    else if(state==DONE)begin
        num <= 0;               //接收完一帧后清零NUM和接收寄存器
        temp_data <= 8'd0;
    end
    else if(neg_ps2_clk)begin
        num <= num + 1;
        temp_data <= {ps2_dat_r2,temp_data[9:1]};   //由左边移入临时寄存器
    end
end

always@(posedge clk_i or posedge arst_i)begin
    case(state)
        RECEIVE: state <= (num==12)?DONE : state;
        DONE : state <= RECEIVE;
    endcase
end

always @(posedge clk_i or posedge arst_i) begin
    if(state==DONE)begin
        data_o <= temp_data;
    end
end
assign valid_o = (state==DONE);

endmodule